<template>
  <a-modal
    v-model:open="dialogVisible"
    @after-visible-change="handleDialogOpened"
    :footer="null"
    :width="800"
    :bodyStyle="{ height: scrollHeight, padding: '0' }"
    :maskClosable="false"
    :keyboard="false"
    :closable="false"
    :fullscreen="fullScreen"
    class="user-ext-dialog"
  >
    <template #title>
      <div style="display: flex; justify-content: space-between; align-content: center; height: 23px; box-sizing: border-box">
        <div style="font-size: 1.2em">预览</div>
        <div style="display: flex; flex-direction: row; justify-content: center">
          <div @click.stop="requestFullScreen" class="full-screen btn">
            <s-v-g-icon style="width: 20px; height: 20px" :name="fullScreen ? 'FullScreenMinimize' : 'FullScreenMaximize'"/>
          </div>
          <div @click.stop="handleDialogClosed" class="close btn">
            <s-v-g-icon style="width: 20px; height: 20px" name="close"/>
          </div>
        </div>
      </div>
    </template>
    <a-scrollbar :style="{ height: scrollHeight }">
      <div ref="editorRef"></div>
    </a-scrollbar>
    <template #footer>
      <slot name="footer">
      </slot>
    </template>
  </a-modal>
</template>

<script>
import { basicSetup, EditorView } from "codemirror"
import { EditorState, Compartment } from "@codemirror/state"
import { json } from "@codemirror/lang-json"
import { computed, ref, shallowRef, toRaw, watch } from "vue"
import SVGIcon from "@/components/common/SVGIcon.vue"

export default {
  name: 'JsonEditor',
  components: {
    SVGIcon
  },
  props: {
    visible: {
      type: Boolean,
      required: true
    },
    code: {
      type: String,
      required: true
    }
  },
  emits: ["update:visible"],
  setup(props, { emit }) {
    let language = new Compartment
    let tabSize = new Compartment
    const editorRef = shallowRef()
    const state = shallowRef(null)
    const view = shallowRef(null)

    const dialogVisible = ref(props.visible)
    watch(() => props.visible, () => dialogVisible.value = props.visible)

    const fullScreen = ref(false)
    function requestFullScreen() {
      fullScreen.value = !fullScreen.value
    }

    const scrollHeight = computed(() => {
      if (fullScreen.value) {
        return "calc(100vh - 54px - 64px - 40px)"
      } else {
        return "calc(100vh - 54px - 64px - 30vh - 40px)"
      }
    })

    function handleDialogOpened(visible) {
      if (!visible) return
      
      if(view.value) {
        view.value.destroy()
      }

      state.value = EditorState.create({
        doc: props.code,
        extensions: [
          basicSetup,
          language.of(json()),
          tabSize.of(EditorState.tabSize.of(4))
        ]
      })
      view.value = new EditorView({
        state: toRaw(state.value),
        parent: editorRef.value
      })
    }

    function handleDialogClosed() {
      dialogVisible.value = false
      emit("update:visible", false)
    }

    return {
      state,
      view,
      editorRef,
      dialogVisible,
      fullScreen,
      requestFullScreen,
      scrollHeight,
      handleDialogOpened,
      handleDialogClosed
    }
  }
}
</script>

<style scoped>
div.btn {
  cursor: pointer;
}

div.btn + div.btn {
  cursor: pointer;
  margin-left: 10px;
}

div.btn:hover {
  color: var(--ant-primary-color)
}

.dialog-footer {
  display: flex;
  justify-content: space-around;
}
</style>